using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;

namespace ListViewDragDrop.Controls.Utilities
{
	/// <summary>
	/// Provides access to the mouse location by calling unmanaged code.
	/// </summary>
	/// <remarks>
	/// This class was written by Dan Crevier (Microsoft).  

	/// </remarks>
	public class MouseUtilities
	{
		[StructLayout( LayoutKind.Sequential )]
		private struct Win32Point
		{
			public Int32 X;
			public Int32 Y;
		};

		[DllImport( "user32.dll" )]
		private static extern bool GetCursorPos( ref Win32Point pt );

		[DllImport( "user32.dll" )]
		private static extern bool ScreenToClient( IntPtr hwnd, ref Win32Point pt );

		/// <summary>
		/// Returns the mouse cursor location.  This method is necessary during 
		/// a drag-drop operation because the WPF mechanisms for retrieving the
		/// cursor coordinates are unreliable.
		/// </summary>
		/// <param name="relativeTo">The Visual to which the mouse coordinates will be relative.</param>
		public static Point GetMousePosition( Visual relativeTo )
		{
			Win32Point mouse = new Win32Point();
			GetCursorPos( ref mouse );

			// Using PointFromScreen instead of Dan Crevier's code (commented out below)
		
			return relativeTo.PointFromScreen( new Point( (double)mouse.X, (double)mouse.Y ) );

			#region Commented Out
			//System.Windows.Interop.HwndSource presentationSource =
			//    (System.Windows.Interop.HwndSource)PresentationSource.FromVisual( relativeTo );
			//ScreenToClient( presentationSource.Handle, ref mouse );
			//GeneralTransform transform = relativeTo.TransformToAncestor( presentationSource.RootVisual );
			//Point offset = transform.Transform( new Point( 0, 0 ) );
			//return new Point( mouse.X - offset.X, mouse.Y - offset.Y );
			#endregion // Commented Out
		}
        /// <summary>
        /// Serializes <code>obj</code> into a XAML string
        /// </summary>
        /// <param name="obj">Object to serialize</param>
        /// <returns>Serialized XAML version of <code>obj</code></returns>
        public static string SerializeObject(object obj)
        {
            
            return XamlWriter.Save(obj);
        }

        /// <summary>
        /// Converts XAML serialized string back into object
        /// </summary>
        /// <param name="xaml">XAML serialized object</param>
        /// <returns>Object represented by XAML string</returns>
        public static object DeserializeObject(string xaml)
        {
            return XamlReader.Load(new XmlTextReader(new StringReader(xaml)));
        }

        /// <summary>
        /// Clones an object
        /// </summary>
        /// <param name="obj">object to clone</param>
        /// <returns>Clone of <code>obj</code></returns>
        public static object CloneElement(object obj)
        {
            return DeserializeObject(SerializeObject(obj));
        }
	}
}